package com.ytrsoft.io;

import com.ytrsoft.bean.IOType;

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;

public class IOOutputStream extends PrintStream {

    private IOType type;
    private IOOutputStreamListener listener;

    public IOOutputStream(OutputStream out) {
        super(out, true);
        this.type = IOType.STDOUT;
        if (out.equals(System.err)) {
            this.type = IOType.STDERR;
        }
    }

    @Override
    public void print(String x) {
        super.print(x);
        writeForData(x, false);
    }

    @Override
    public void print(char x) {
        String s = String.valueOf(x);
        super.print(x);
        writeForData(s, false);
    }

    @Override
    public void print(long x) {
        String s = String.valueOf(x);
        super.print(x);
        writeForData(s, false);
    }

    @Override
    public void print(boolean x) {
        String s = String.valueOf(x);
        super.print(x);
        writeForData(s, false);
    }

    @Override
    public void print(double x) {
        String s = String.valueOf(x);
        super.print(x);
        writeForData(s, false);
    }

    public void print(float x) {
        String s = String.valueOf(x);
        super.print(x);
        writeForData(s, false);
    }

    @Override
    public void print(int x) {
        String s = String.valueOf(x);
        super.print(x);
        writeForData(s, false);
    }

    @Override
    public void print(char[] x) {
        String s = String.valueOf(x);
        super.print(x);
        writeForData(s, false);
    }

    @Override
    public void print(Object x) {
        String s = String.valueOf(x);
        super.print(x);
        writeForData(s, false);
    }


    @Override
    public void println(String x) {
        synchronized (this) {
            String s = String.valueOf(x);
            writeForData(s, true);
            write(s);
            newLine();
        }
    }

    @Override
    public void println(Object x) {
        synchronized (this) {
            String s = String.valueOf(x);
            writeForData(s, true);
            write(s);
            newLine();
        }
    }

    @Override
    public void println(int x) {
        synchronized (this) {
            String s = String.valueOf(x);
            writeForData(s, true);
            write(s);
            newLine();
        }
    }

    @Override
    public void println(char x) {
        synchronized (this) {
            String s = String.valueOf(x);
            writeForData(s, true);
            write(s);
            newLine();
        }
    }

    @Override
    public void println(long x) {
        synchronized (this) {
            String s = String.valueOf(x);
            writeForData(s, true);
            write(s);
            newLine();
        }
    }

    @Override
    public void println(float x) {
        synchronized (this) {
            String s = String.valueOf(x);
            writeForData(s, true);
            write(s);
            newLine();
        }
    }

    @Override
    public void println(char[] x) {
        synchronized (this) {
            String s = String.valueOf(x);
            writeForData(s, true);
            write(s);
            newLine();
        }
    }

    @Override
    public void println(double x) {
        synchronized (this) {
            String s = String.valueOf(x);
            writeForData(s, true);
            write(s);
            newLine();
        }
    }

    @Override
    public void println(boolean x) {
        synchronized (this) {
            String s = String.valueOf(x);
            writeForData(s, true);
            write(s);
            newLine();
        }
    }

    @Override
    public void println() {
        writeForData("", true);
        newLine();
    }

    private void write(String s) {
        try {
            super.write(s.getBytes());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private void newLine() {
        String s = System.lineSeparator();
        write(s);
    }


    public void setOnIOOutputStreamListener(IOOutputStreamListener listener) {
        this.listener = listener;
    }

    private void writeForData(String body, boolean hasNewLine) {
        if (this.listener != null) {
            this.listener.out(type, body, hasNewLine);
        }
    }

}